import UIKit
@available(iOSApplicationExtension, unavailable)
internal extension IQKeyboardManager {
    private struct AssociatedKeys {
        static var textFieldView: Int = 0
        static var topViewBeginOrigin: Int = 0
        static var topViewBeginSafeAreaInsets: Int = 0
        static var rootViewController: Int = 0
        static var rootViewControllerWhilePopGestureRecognizerActive: Int = 0
        static var topViewBeginOriginWhilePopGestureRecognizerActive: Int = 0
    }
    weak var textFieldView: UIView? {
        get {
            return (objc_getAssociatedObject(self, &AssociatedKeys.textFieldView) as? WeakObjectContainer)?.object as? UIView
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.textFieldView, WeakObjectContainer(object: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    var topViewBeginOrigin: CGPoint {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.topViewBeginOrigin) as? CGPoint ?? IQKeyboardManager.kIQCGPointInvalid
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.topViewBeginOrigin, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    var topViewBeginSafeAreaInsets: UIEdgeInsets {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.topViewBeginSafeAreaInsets) as? UIEdgeInsets ?? .zero
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.topViewBeginSafeAreaInsets, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    weak var rootViewController: UIViewController? {
        get {
            return (objc_getAssociatedObject(self, &AssociatedKeys.rootViewController) as? WeakObjectContainer)?.object as? UIViewController
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.rootViewController, WeakObjectContainer(object: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    weak var rootViewControllerWhilePopGestureRecognizerActive: UIViewController? {
        get {
            return (objc_getAssociatedObject(self, &AssociatedKeys.rootViewControllerWhilePopGestureRecognizerActive) as? WeakObjectContainer)?.object as? UIViewController
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.rootViewControllerWhilePopGestureRecognizerActive, WeakObjectContainer(object: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    var topViewBeginOriginWhilePopGestureRecognizerActive: CGPoint {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.topViewBeginOriginWhilePopGestureRecognizerActive) as? CGPoint ?? IQKeyboardManager.kIQCGPointInvalid
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.topViewBeginOriginWhilePopGestureRecognizerActive, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    @objc func textFieldViewDidBeginEditing(_ notification: Notification) {
        guard let object = notification.object as? UIView, let isKeyWindow = object.window?.isKeyWindow, isKeyWindow else {
            return
        }
        let startTime = CACurrentMediaTime()
        showLog("📝>>>>> \(#function) started >>>>>", indentation: 1)
        showLog("Notification Object:\(notification.object ?? "NULL")")
        textFieldView = notification.object as? UIView
        if overrideKeyboardAppearance, let textInput = textFieldView as? UITextInput, textInput.keyboardAppearance != keyboardAppearance {
            if let textFieldView = textFieldView as? UITextField {
                textFieldView.keyboardAppearance = keyboardAppearance
            } else if  let textFieldView = textFieldView as? UITextView {
                textFieldView.keyboardAppearance = keyboardAppearance
            }
            textFieldView?.reloadInputViews()
        }
        if privateIsEnableAutoToolbar() {
            if let textView = textFieldView as? UIScrollView, textView.responds(to: #selector(getter: UITextView.isEditable)),
                textView.inputAccessoryView == nil {
                self.addToolbarIfRequired()
            } else {
                addToolbarIfRequired()
            }
        } else {
            removeToolbarIfRequired()
        }
        resignFirstResponderGesture.isEnabled = privateShouldResignOnTouchOutside()
        textFieldView?.window?.addGestureRecognizer(resignFirstResponderGesture)   
        if privateIsEnabled() == false {
            restorePosition()
            topViewBeginOrigin = IQKeyboardManager.kIQCGPointInvalid
            topViewBeginSafeAreaInsets = .zero
        } else {
            if topViewBeginOrigin.equalTo(IQKeyboardManager.kIQCGPointInvalid) {   
                rootViewController = textFieldView?.parentContainerViewController()
                if let controller = rootViewController {
                    if rootViewControllerWhilePopGestureRecognizerActive == controller {
                        topViewBeginOrigin = topViewBeginOriginWhilePopGestureRecognizerActive
                    } else {
                        topViewBeginOrigin = controller.view.frame.origin
                        topViewBeginSafeAreaInsets = controller.view.safeAreaInsets
                    }
                    rootViewControllerWhilePopGestureRecognizerActive = nil
                    topViewBeginOriginWhilePopGestureRecognizerActive = IQKeyboardManager.kIQCGPointInvalid
                    self.showLog("Saving \(controller) beginning origin: \(self.topViewBeginOrigin)")
                }
            }
            if keyboardShowing,
                let textFieldView = textFieldView,
                textFieldView.isAlertViewTextField() == false {
                self.adjustPosition()
            }
        }
        let elapsedTime = CACurrentMediaTime() - startTime
        showLog("📝<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
    }
    @objc func textFieldViewDidEndEditing(_ notification: Notification) {
        guard let object = notification.object as? UIView, let isKeyWindow = object.window?.isKeyWindow, isKeyWindow else {
            return
        }
        let startTime = CACurrentMediaTime()
        showLog("📝>>>>> \(#function) started >>>>>", indentation: 1)
        showLog("Notification Object:\(notification.object ?? "NULL")")
        textFieldView?.window?.removeGestureRecognizer(resignFirstResponderGesture)
        if let textView = textFieldView as? UIScrollView, textView.responds(to: #selector(getter: UITextView.isEditable)) {
            if isTextViewContentInsetChanged {
                self.isTextViewContentInsetChanged = false
                if textView.contentInset != self.startingTextViewContentInsets {
                    self.showLog("Restoring textView.contentInset to: \(self.startingTextViewContentInsets)")
                    UIView.animate(withDuration: animationDuration, delay: 0, options: animationCurve, animations: { () -> Void in
                        textView.contentInset = self.startingTextViewContentInsets
                        textView.scrollIndicatorInsets = self.startingTextViewScrollIndicatorInsets
                    }, completion: { (_) -> Void in })
                }
            }
        }
#if swift(>=5.7)
        if #available(iOS 16.0, *), let textView = object as? UITextView, textView.isFindInteractionEnabled {
        } else {
            textFieldView = nil
        }
 #else
        textFieldView = nil
#endif
        let elapsedTime = CACurrentMediaTime() - startTime
        showLog("📝<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
    }
}
